#include <iostream>
#include <cstdlib>
#include <string>
#include <unistd.h>
#include <cstring>
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include "err.hpp"

using namespace std;
//./tcp_client serverip serverport
void Usage(string u)
{
    cout << "Usage:\n\t" << u << " serverip serverport" << endl;
}
int main(int argv, char *argc[])
{
    if (argv != 3)
    {
        Usage(argc[0]);
        exit(USAGE_ERROR);
    }
    string serverip = argc[1];
    uint16_t serverport = atoi(argc[2]);
    // 1.创建套接字--打开文件
    int sock = socket(AF_INET, SOCK_STREAM, 0); // SOCK_STREAM流式套接字，用于TCP协议
        // 2.客户端无需用户bind，交给OS
        // 3.客户端不要listen，客户端可以listen，listen之后就不是纯粹的客户端
        // 4.客户端要不要accept？不要，这个是服务器的事
        // 5.客户端使用connect函数请求与服务器进行连接
        /* int connect(int sockfd, const struct sockaddr *addr,socklen_t addrlen);*/
    struct sockaddr_in peer;
    memset(&peer, 0, sizeof(peer));
    peer.sin_family = AF_INET;         // 网络通信
    peer.sin_port = htons(serverport); // 端口号:主机序列转网络序列
    peer.sin_addr.s_addr = inet_addr(serverip.c_str());
    int count = 5;
    while (connect(sock, (struct sockaddr *)&peer, sizeof(peer)) != 0)
    {
        cerr<<"connect error:"<<strerror(errno)<<endl;
        cout << "正在尝试重连...,给你重连的机会还剩：" << count--<<endl;
        if (count <= 0)
            break;
            sleep(1);
    }
    if (count <= 0)
    {
        cerr << "connect error" << endl;
        exit(CONNECT_ERROR);
    }

    //连接成功
    while (true)
    {
        cout << "Enter#";
        string message;
        getline(std::cin, message);
        write(sock, message.c_str(), message.size());
        cout << "Server echo#";
        char buffer[2024];
        ssize_t n = read(sock, buffer, sizeof(buffer) - 1);
        if (n > 0)
        {
            buffer[n] = '\0';
            cout << buffer << endl;
        }else if(n == 0)
        {
            cerr<<"server quit"<<endl;
            break;
        }else 
        {
            cerr<<"read error"<<endl;
            break;
        }
    }
    return 0;
}